<?php

/**
 * Description of VirtualLabs_Rest_Util
 *
 * @author markos
 */
class VirtualLabs_Reserved {

    private $_logger;
    private $baseCoreNumber;
    private $baseCoreSpeed;
    private $baseMemory;
    private $baseDiskSpace;
    private $totalCpu;
    private $totalMemory;

    const CAPACITY_TYPE_MEMORY = 0;
    const CAPACITY_TYPE_CPU = 1;
    const CAPACITY_TYPE_STORAGE = 2;
    const CAPACITY_TYPE_STORAGE_ALLOCATED = 3;
    const CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP = 4;
    const CAPACITY_TYPE_PRIVATE_IP = 5;
    const CAPACITY_TYPE_SECONDARY_STORAGE = 6;
    const CAPACITY_TYPE_VLAN = 7;
    const CAPACITY_TYPE_DIRECT_ATTACHED_PUBLIC_IP = 8;
    const CAPACITY_TYPE_LOCAL_STORAGE = 9;

    public function __construct() {
        $this->_logger = Zend_Registry::get(VirtualLabs_Common::DEBUG_LOG);
        $config = new Zend_Config_Ini(CLOUDSTACK_CONFIG_FILE, APPLICATION_ENV);
        $this->baseCoreNumber = $config->get("base_core_number");
        $this->baseCoreSpeed = $config->get("base_core_speed");
        $this->baseMemory = $config->get("base_memory");
        $this->baseDiskSpace = $config->get("base_disk_space");
        $this->loadTotales();
    }

    public function getTotalCpu() {
        return $this->totalCpu;
    }

    public function getTotalMemory() {
        return $this->totalMemory;
    }

    private function loadTotales() {
        $util = new VirtualLabs_Rest_Util();
        $capacity = $util->listCapacity();
        $this->_logger->debug(print_r($capacity, true));

        if (isset($capacity['listcapacityresponse']['count'])) {
            if ($capacity['listcapacityresponse']['count'] > 0) {
                foreach ($capacity['listcapacityresponse']['capacity'] as $c) {
                    if ($c['type'] == self::CAPACITY_TYPE_CPU) {
                        $this->totalCpu = ($c['capacitytotal']);
                    } else if ($c['type'] == self::CAPACITY_TYPE_MEMORY) {
                        $this->totalMemory = ($c['capacitytotal'] / 1024 / 1024);
                    }
                }
            }
        }
    }

    public function normalize($resources) {
        $r = array();
        $r['memory'] = abs($resources['memory'] / $this->baseMemory);
        $r['cpu'] = abs($resources['cpu'] / $this->baseCoreSpeed);
        return $r;
    }

    public function getReserverdByTimeRange($days = array(), $hours = array()) {

        $reserved = $this->getReservedResources();
//        $this->_logger->debug(print_r($reserved, true));
        $filteredResources = array();

        if (count($days) === 0)
            return;

        foreach ($days as $d) {
            if (count($hours) === 0) {
                foreach ($reserved['dias'][$d]['memory'] as $key => $value) {
                    $filteredResources[$d][$key]['memory'] += $value;
                }
                foreach ($reserved['dias'][$d]['cpu'] as $key => $value) {
                    $filteredResources[$d][$key]['cpu'] += $value;
                }
            } else {
                $i = 0;
                for ($count = $hours['inicio']; $count < $hours['fin']; $count++) {
                    if (strlen($count) == 1) {
                        $tmpCount = "0$count";
                    } else {
                        $tmpCount = "$count";
                    }
                    foreach ($reserved['dias'][$d]['memory'] as $value) {
                        if ($value['hora'] === $tmpCount) {
                            $filteredResources[$d]['memory'] += $value['memory'];
                        }
                    }
                    $filteredResources[$d]['memory'] = $filteredResources[$d]['memory'];
                    foreach ($reserved['dias'][$d]['cpu'] as $value) {
                        if ($value['hora'] === $tmpCount) {
                            $filteredResources[$d]['cpu'] += $value['cpu'];
                        }
                    }
                    $filteredResources[$d]['cpu'] = $filteredResources[$d]['cpu'];
                    $i++;
                }
                if ($i == 0) {
                    $i++;
                }
                $filteredResources[$d]['memory'] = $filteredResources[$d]['memory'] / $i;
                $filteredResources[$d]['cpu'] = $filteredResources[$d]['cpu'] / $i;
            }
        }

        foreach ($filteredResources as $k => $v) {
            $filteredResources[$k] = $this->normalize($v);
        }
        $this->_logger->debug(print_r($filteredResources, true));
        return $filteredResources;
    }

    /**
     * Obtiene la carga total de los laboratorios virtuales del sistema. La informacion es devuelta
     * en formato de arreglo. La estructura se organiza en horarios por dia.
     * 
     */
    public function getReservedResources() {
        $labDao = new VirtualLabs_Admin_Laboratorio();
        $laboratorios = $labDao->getLaboratorios(array('*'));

        $perfiles = $this->getConfiguracionEncendido($laboratorios);
        $load = $this->getLabLoad($laboratorios);

        $days = array('Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa');
        $normalized = $this->normalizeConfigs($perfiles, $load);
        $scheduleInfo = array('plataform_resources' => $normalized['platform_resources']);
        foreach ($days as $d) {
            foreach ($normalized[$d] as $key => $data) {
                $tmpCpu = array('hora' => "$key", 'cpu' => $data['cpu']);
                $tmpMemory = array('hora' => "$key", 'memory' => $data['memory']);
                $scheduleInfo['dias'][$d]['memory'][] = $tmpMemory;
                $scheduleInfo['dias'][$d]['cpu'][] = $tmpCpu;
            }
        }
        return $scheduleInfo;
    }

    /**
     * Obtiene la carga total de los laboratorios virtuales del sistema. La informacion es devuelta
     * en formato de arreglo. La estructura se organiza en horarios por dia.
     * 
     */
    public function getReservedResourcesVMUnits() {
        $labDao = new VirtualLabs_Admin_Laboratorio();
        $laboratorios = $labDao->getLaboratorios(array('*'));
        $config = new Zend_Config_Ini(CLOUDSTACK_CONFIG_FILE, APPLICATION_ENV);
        $baseMemory = $config->get("base_memory");
        $baseCpuSpeed = $config->get("base_core_speed");
        $baseCpuNumber = $config->get("base_core_number");

        $perfiles = $this->getConfiguracionEncendido($laboratorios);
        $load = $this->getLabLoad($laboratorios);

        $days = array('Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa');
        $normalized = $this->normalizeConfigs($perfiles, $load);
        $normalized['platform_resources']['memory'] = round((str_replace(".", "", $normalized['platform_resources']['memory']) / $baseMemory), 0);
        $normalized['platform_resources']['cpu'] = round((str_replace(".", "", $normalized['platform_resources']['cpu']) / ($baseCpuNumber * $baseCpuSpeed)), 0);
        $normalized['platform_resources']['unit'] = round((($normalized['platform_resources']['memory'] + $normalized['platform_resources']['cpu']) / 2), 0);
        $scheduleInfo = array('plataform_resources' => $normalized['platform_resources']);
        foreach ($days as $d) {
            foreach ($normalized[$d] as $key => $data) {
                $cpuUnits = ($data['cpu'] / ($baseCpuNumber * $baseCpuSpeed));
                $memoryUnits = ($data['memory'] / $baseMemory);
                $units = round($memoryUnits);
                if($cpuUnits < $memoryUnits) {
                    $units = round($cpuUnits);
                }
                //$units = round((($cpuUnits + $memoryUnits) / 2), 0);
                $scheduleInfo['dias'][$d][] = array('hora' => "$key", 'unit' => $units);
            }
        }
        return $scheduleInfo;
    }

    public function getPlatformResources() {
        $util = new VirtualLabs_Rest_Util();
        $capacity = $util->listCapacity();
        $this->_logger->debug(print_r($capacity, true));
        $response = array();
        if (isset($capacity['listcapacityresponse']['count'])) {
            if ($capacity['listcapacityresponse']['count'] > 0) {
                foreach ($capacity['listcapacityresponse']['capacity'] as $c) {
//                    $this->_logger->debug(print_r($c, true));
                    if ($c['type'] == self::CAPACITY_TYPE_CPU) {
//                        
                        $response['cpu'] = number_format($c['capacitytotal'], 0, ",", ".");
                    } else if ($c['type'] == self::CAPACITY_TYPE_MEMORY) {
//                        retorna en bytes, convertir a mega bytes
                        $response['memory'] = number_format(($c['capacitytotal'] / 1024 / 1024), 0, ",", ".");
                    } else if ($c['type'] == self::CAPACITY_TYPE_STORAGE) {
//                        retorna en bytes, convertir a mega bytes
                        $response['disk'] = number_format(($c['capacitytotal'] / 1024 / 1024), 0, ",", ".");
                    }
                }
            }
        }
        return $response;
    }

    /**
     * Obtiene las configuraciones de encendido para los laboratorios activos en el sistema.
     * 
     * @param type $labs
     * @return array(codigo_laboratorio, perfiles => array())
     * 
     */
    private function getConfiguracionEncendido($labs) {
        $confEncendidoDao = new VirtualLabs_Admin_PerfilEncendido();
        $perfiles = array();
        foreach ($labs as $l) {
            try {
                if (isset($l['codigo_perfil_encendido'])) {
                    $perfil = $confEncendidoDao->getPerfilEncendido(array('*'), array('codigo_perfil_encendido' => array('criteria' => '=', 'value' => $l['codigo_perfil_encendido'])));
                    $perfiles[$l['codigo_laboratorio']] = array('codigo_laboratorio' => $l['codigo_laboratorio'], 'profile' => array('inicio' => $perfil['hora_inicio_dia'], 'fin' => $perfil['hora_fin_dia'], 'dias' => $perfil['dias_encendido']));
                }
            } catch (Exception $e) {
                $this->_logger->err("Error al recuperar la informacion de encendido");
            }
        }
        return $perfiles;
    }

    /**
     * Obtiene la carga total de un laboratorio en terminos de recursos utilizados por sus maquinas virtuales.
     * 
     */
    private function getLabLoad($laboratorios) {
        $vmDao = new VirtualLabs_Admin_Machine();
        $vmCloud = new VirtualLabs_Rest_VirtualLabs_VirtualMachine();
        $load = array();
        foreach ($laboratorios as $l) {
            $virtualMachines = $vmDao->getVirtualMachines(array('*'), array('codigo_laboratorio' => array('criteria' => '=', 'value' => $l['codigo_laboratorio'])));
            $cpunumber = 0;
            $disk = 0;
            $memory = 0;
            foreach ($virtualMachines as $v) {
                $vmConfig = Zend_Json_Decoder::decode($vmCloud->listVM($v['codigo_vm']));
                $this->_logger->debug("VIRTUAL MACHINE : " . print_r($vmConfig, true));
                if (isset($vmConfig['listvirtualmachinesresponse'])) {
                    $memory+= $vmConfig['listvirtualmachinesresponse']['virtualmachine'][0]['memory'];
                    $cpunumber+= $vmConfig['listvirtualmachinesresponse']['virtualmachine'][0]['cpuspeed'];
//                    $disk+= $vmConfig['listvirtualmachinesresponse']['virtualmachine'][0]['cpuspeed'];
                }
            }
            $load[$l['codigo_laboratorio']] = array('codigo_laboratorio' => $l['codigo_laboratorio'], 'cpunumber' => $cpunumber, 'memory' => $memory);
        }
        return $load;
    }

    private function fillEmpty($schedule) {
        $hours = array('06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '22', '23', '00', '01', '02', '03', '04', '05');
        $days = array('Do', 'Lu', 'Ma', 'Mi', 'Ju', 'Vi', 'Sa');
        foreach ($days as $d) {
            if (!isset($schedule[$d])) {
                foreach ($hours as $h) {
                    $schedule[$d][$h] = array('cpu' => 0, 'memory' => 0);
                }
            } else {
                foreach ($hours as $h) {
                    if (!isset($schedule[$d][$h])) {
                        $schedule[$d][$h] = array('cpu' => 0, 'memory' => 0);
                    }
                }
            }
            ksort($schedule[$d]);
        }
        return $schedule;
    }

    /**
     * Normaliza la informacion de los perfiles de encendido para los dias de la semana.
     * 
     * @param type $profiles
     */
    private function normalizeConfigs($profiles, $loads) {
        $normalized = array('platform_resources' => $this->getPlatformResources());
        foreach ($profiles as $lab_code => $p) {
            $init = substr($p['profile']['inicio'], 0, 2);
            $final = substr($p['profile']['fin'], 0, 2);
            $dias = explode(",", $p['profile']['dias']);
            foreach ($dias as $d) {
//                $normalized[$d][$init]['cpu'] += number_format($loads[$lab_code]['cpunumber'] * 100 / $normalized['platform_resources']['cpu']);
//                $normalized[$d][$init]['memory'] += number_format($loads[$lab_code]['memory'] * 100 / $normalized['platform_resources']['memory']);
                $normalized[$d][$init]['cpu'] += $loads[$lab_code]['cpunumber'];
                $normalized[$d][$init]['memory'] += $loads[$lab_code]['memory'];
                for ($count = $init + 1; $count < $final; $count++) {
                    if (strlen($count) == 1) {
                        $tmpCount = "0$count";
                    } else {
                        $tmpCount = "$count";
                    }
//                    $normalized[$d][$tmpCount]['cpu'] += number_format($loads[$lab_code]['cpunumber'] * 100 / $normalized['platform_resources']['cpu']);
//                    $normalized[$d][$tmpCount]['memory'] += number_format($loads[$lab_code]['memory'] * 100 / $normalized['platform_resources']['memory']);
                    $normalized[$d][$tmpCount]['cpu'] += $loads[$lab_code]['cpunumber'];
                    $normalized[$d][$tmpCount]['memory'] += $loads[$lab_code]['memory'];
                }
//                $normalized[$final][$d]['cpu'] += $loads[$lab_code]['cpunumber'] * 100 / $normalized['platform_resources']['cpu'];
//                $normalized[$final][$d]['memory'] += $loads[$lab_code]['memory'] * 100 / $normalized['platform_resources']['memory'];
            }
        }
        return $this->fillEmpty($normalized);
    }

}
?>
    
